home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / shanghai.000 / shanghai / shanghai-1.0 / game.c < prev    next >
C/C++ Source or Header  |  1995-05-31  |  22KB  |  742 lines

  1. #include <memory.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. #include <unistd.h>
  6.  
  7. #include "forms.h"
  8. #include "board.h"
  9. #include "game.h"
  10. #include "mapdata.h"
  11.  
  12. /* This parameter allows for tuning the performance of the depthscan
  13.    algorithm by selecting between different heuristics; PRIORITY == 1
  14.    seems to work best, but it is probably worthwhile to think a
  15.    little more about good heuristics... */
  16.  
  17. #define PRIORITY     /* 0 */    1    /* 2 */ /* 3 */
  18.  
  19. /* Select different methods for drawing suggestings; currently
  20.    DRAWSUGGEST == 0 is fasted, but that might change, if draw_area()
  21.    can be optimized */
  22.  
  23. #define DRAWSUGGEST     0    /* 1 */
  24.  
  25. int default_isfastgame = 0;
  26.  
  27. static __inline__ int chk(unsigned char *occ,unsigned char *arr)
  28. {
  29.   int     i;
  30.   
  31.   for (i = 0; arr[i] != NIL; i++)
  32.     if (occ[arr[i]] != NIL) return(arr[i]);
  33.   return(NIL);
  34. }
  35.  
  36. static __inline__ int tile_is_removable(unsigned char *occ,int tile)
  37. {
  38.   register unsigned char top;
  39.  
  40.   return(occ[tile] != NIL &&
  41.      (((top = board[tile].top) == NIL || occ[top] == NIL) &&
  42.       (chk(occ,board[tile].left) == NIL ||
  43.        chk(occ,board[tile].right) == NIL)));
  44. }
  45.  
  46. static __inline__ int match_count(unsigned char *occ,unsigned char *lookup,
  47.                   unsigned char *inverse)
  48. {
  49.   unsigned char   i,j,k,l;
  50.   int             count = 0,tmpcount;
  51.   
  52.   if (inverse)
  53.     memset(inverse,NIL,sizeof(unsigned char)*144);
  54.   for (i = 144/4; i--;) {
  55.     tmpcount = 0;
  56.     l = NIL;
  57.     for (j = 4; j--;) {
  58.       k = lookup[4*i+j];
  59.       if (tile_is_removable(occ,k)) {
  60.     if (l != NIL && inverse) {inverse[l] = 1; inverse[k] = 1;}
  61.     l = k;
  62.     tmpcount++; } }
  63.     if (tmpcount >= 2)
  64.       count += tmpcount-1; }
  65.   return(count);
  66. }
  67.  
  68. static int find_unambiguous(BoardRec *board_rec,unsigned char *occ,
  69.                 unsigned char *sel0,unsigned char *sel1)
  70. {
  71.   unsigned char * const lookup = board_rec->lookup;
  72.   unsigned char   i,j,k,isOcc;
  73.   int             count;
  74.   int             remain = 0,m = NIL,n = NIL;
  75.   
  76.   *sel0 =
  77.   *sel1 = NIL;
  78.   for (i = 144/4; i--; ) {
  79.     count = isOcc = 0;
  80.     for (j = 4; j--; ) {
  81.       k = lookup[4*i+j];
  82.       if (occ[k] == NIL || tile_is_removable(occ,k)) {
  83.       if (occ[k] != NIL)
  84.         isOcc++;
  85.       count++; } }
  86.     if (isOcc >= 2) {
  87.       remain += isOcc;
  88.       if (count == 4)
  89.     for (j = 4; j--; ) {
  90.       k = lookup[4*i+j];
  91.       if (occ[k] != NIL) if (*sel0 == NIL)
  92.         *sel0 = k;
  93.       else {
  94.         *sel1 = k; return(1); } }
  95.       else if (isOcc == 2 && remain == 2)
  96.     for (j = 4; j--; ) {
  97.       k = lookup[4*i+j];
  98.       if (tile_is_removable(occ,k))
  99.         if (m == NIL) m = k;
  100.         else          n = k; } } }
  101.   if (remain == 2) {
  102.     *sel0 = m; *sel1 = n;
  103.     return(1); }
  104.   return(0);
  105. }
  106.  
  107. #if PRIORITY == 1 || PRIORITY == 3
  108. static unsigned char const * cur_weight = NULL;
  109. #if PRIORITY == 3
  110. static int (*pri_comp)(const void *,const void *) = NULL;
  111. static int pricount = 0;
  112. static int pri_comp0(const void *pri1,const void *pri2)
  113. {
  114.   return((int)*(unsigned char *)pri1 - (int)*(unsigned char *)pri2);
  115. }
  116. static int pri_comp2(const void *pri1,const void *pri2)
  117. {
  118.   return((int)*(unsigned char *)pri1 - (int)*(unsigned char *)pri2);
  119. }
  120. static int pri_comp1(const void *pri1,const void *pri2)
  121. #else
  122. #endif
  123. #endif
  124. #if PRIORITY != 3
  125. static int pri_comp(const void *pri1,const void *pri2)
  126. #endif
  127. {
  128. #if PRIORITY == 0
  129.     return((int)*(unsigned char *)pri1 - (int)*(unsigned char *)pri2);
  130. #else
  131.     return(16*cubic((int)((unsigned char *)pri1)[0]
  132.                -(int)((unsigned char *)pri2)[0])
  133.        +(int)cur_weight[((unsigned char *)pri1)[1]]
  134.        +(int)cur_weight[((unsigned char *)pri1)[2]]
  135.        -(int)cur_weight[((unsigned char *)pri2)[1]]
  136.        -(int)cur_weight[((unsigned char *)pri2)[2]]);
  137. #endif
  138. }
  139.  
  140. static void depth_scan_findpairs(BoardRec *board_rec)
  141. {
  142.   DepthScanRec  * const depthscan = &board_rec->depthscan;
  143.   unsigned char * const occ       = depthscan->occ;
  144.   unsigned char * const stack     = depthscan->stack;
  145.   unsigned char * const lookup    = board_rec->lookup;
  146.   #if PRIORITY == 2 || PRIORITY == 3
  147.   unsigned char * const weight    = board_rec->weight;
  148.   #endif
  149.   int sp = depthscan->sp,pp;
  150.   int pair,sel1,sel2;
  151.   int tile1,tile2;
  152.   int pri;
  153.  
  154.   for (pair = 144/4; pair--;)
  155.     for (sel1 = 4; --sel1;) {
  156.       tile1 = lookup[4*pair+sel1];
  157.       if (tile_is_removable(occ,tile1))
  158.     for (sel2 = sel1; sel2--;) {
  159.       tile2 = lookup[4*pair+sel2];
  160.       if (tile_is_removable(occ,tile2)) {
  161.         occ[tile1] = occ[tile2] = NIL;
  162.         if (sp < sizeof(depthscan->stack)-3 &&
  163.         ((pri = match_count(occ,lookup,NULL)) != 0 ||
  164.         depthscan->remain == 2)) {
  165.               #if PRIORITY == 2 || PRIORITY == 3
  166.               #if PRIORITY == 3
  167.           if (pri_comp == pri_comp2)
  168.               #endif
  169.           pri = 2*cubic(pri)+((int)weight[tile1]+(int)weight[tile2])/8-
  170.             sqr((int)weight[tile1]-(int)weight[tile2])/128+32;
  171.           stack[sp++] = pri > 255 ? 255 : pri < 0 ? 0 : pri;
  172.           #else
  173.           stack[sp++] = pri;
  174.               #endif
  175.           stack[sp++] = tile1;
  176.           stack[sp++] = tile2; }
  177.         occ[tile1] = 4*pair+sel1;
  178.         occ[tile2] = 4*pair+sel2; } } }
  179.   if (sp != (pp = depthscan->pp)) {
  180.     int i,j;
  181.     #if PRIORITY == 1 || PRIORITY == 3
  182.     cur_weight = board_rec->weight;
  183.     #endif
  184.     qsort(stack+pp,(sp-pp)/3,3,pri_comp);
  185.     for (i = sp, j = sp = pp; j < i; j += 3) {
  186.       stack[sp++] = stack[j+1];
  187.       stack[sp++] = stack[j+2]; } }
  188.   depthscan->sp = sp;
  189.   return;
  190. }
  191.  
  192. static void depth_scan_update_ideal(BoardRec *board_rec)
  193. {
  194.   DepthScanRec  * const depthscan = &board_rec->depthscan;
  195.   unsigned char * const occ       = depthscan->occ;
  196.   unsigned char * const stack     = depthscan->stack;
  197.   unsigned char * const lookup    = board_rec->lookup;
  198.   unsigned char * const ideal     = board_rec->ideal;
  199.   unsigned char * const weight    = board_rec->weight;
  200.   unsigned char * const history   = board_rec->history;
  201.   unsigned char tile;
  202.   int sp     = depthscan->sp;
  203.   int remain = depthscan->remain;
  204.  
  205.   while (sp != 0) {
  206.     occ[ideal[remain++] = stack[sp-5]] = stack[sp-3];
  207.     occ[ideal[remain++] = stack[sp-6]] = stack[sp-4];
  208.     sp = stack[sp-1] + 256*stack[sp-2]; }
  209.   depthscan->remain = remain;
  210.   while (remain < 144) {
  211.     ideal[remain++] = lookup[history[142-remain]];
  212.     ideal[remain++] = lookup[history[144-remain]]; }
  213.   for (tile = 144; tile--;)
  214.     weight[ideal[tile]] = tile+1;
  215.   depthscan->sp     =
  216.   depthscan->pp     = 0;
  217.   return;
  218. }
  219.  
  220. enum dsStatus depth_scan(BoardRec *board_rec)
  221. {
  222.   DepthScanRec  * const depthscan = &board_rec->depthscan;
  223.   unsigned char * const occ       = depthscan->occ;
  224.   unsigned char * const stack     = depthscan->stack;
  225.   int sp;
  226.   int pp;
  227.   int remain;
  228.   unsigned char tile1,tile2;
  229.  
  230.   if (depthscan->status != dsBusy)
  231.     return(depthscan->status == dsSuccessSelected ?
  232.        dsSuccess : depthscan->status);
  233.   depth_scan_findpairs(board_rec);
  234.   sp     = depthscan->sp;
  235.   pp     = depthscan->pp;
  236.   remain = depthscan->remain;
  237.  next_branch:
  238.   while (pp != 0 && sp == pp) {
  239.     #if PRIORITY == 3
  240.     #define PRSWITCH 8192
  241.     if ((++pricount % PRSWITCH) == 0) {
  242.       printf("switch\n");
  243.       if (pricount == 3*PRSWITCH) {pricount = 0; pri_comp = pri_comp0; }
  244.       else if (pricount == 2*PRSWITCH) pri_comp = pri_comp2;
  245.       else pri_comp = pri_comp1; }
  246.     #endif
  247.     remain += 2;
  248.     occ[stack[sp-5]] = stack[sp-3];
  249.     occ[stack[sp-6]] = stack[sp-4];
  250.     pp = stack[sp-1] + 256*stack[sp-2];
  251.     sp -= 6; }
  252.   if (sp != 0)
  253.     if (sp < sizeof(depthscan->stack)-6+2) {
  254.       stack[sp++]      = occ[stack[sp-2]];
  255.       stack[sp++]      = occ[stack[sp-2]];
  256.       stack[sp++]      = pp/256;
  257.       stack[sp++]      = pp%256;
  258.       occ[stack[sp-5]] =
  259.       occ[stack[sp-6]] = NIL;
  260.       pp = sp;
  261.       remain -= 2;
  262.       while (sp < sizeof(depthscan->stack)-6 &&
  263.          find_unambiguous(board_rec,occ,&tile1,&tile2)) {
  264.     stack[sp++] = tile1;
  265.     stack[sp++] = tile2;
  266.     stack[sp++] = occ[tile1];
  267.     stack[sp++] = occ[tile2];
  268.     stack[sp++] = pp/256;
  269.     stack[sp++] = pp%256;
  270.     pp          = sp;
  271.     occ[tile1]  =
  272.     occ[tile2]  = NIL;
  273.     remain -= 2; }
  274.       if (remain == 0)
  275.     depthscan->status = dsSuccess; }
  276.     else {
  277.       sp -= 2;
  278.       goto next_branch; }
  279.   else
  280.     depthscan->status = remain ? dsFail : dsSuccess;
  281.   depthscan->sp     = sp;
  282.   depthscan->pp     = pp;
  283.   depthscan->remain = remain;
  284.   if (depthscan->status == dsSuccess)
  285.     depth_scan_update_ideal(board_rec);
  286.   if (depthscan->status != dsBusy)
  287.     update_info_box(board_rec);
  288.   return(depthscan->status);
  289. }
  290.  
  291. static int is_board_ideal(BoardRec *board_rec)
  292. {
  293.   unsigned char * const lookup    = board_rec->lookup;
  294.   unsigned char * const ideal     = board_rec->ideal;
  295.   unsigned char * const weight    = board_rec->weight;
  296.   unsigned char * const history   = board_rec->history;
  297.   int           i,j,remain,hist;
  298.   unsigned char tile1,tile2,occ[144];
  299.  
  300.   if ((remain = board_rec->remain) == 0)
  301.     return(1);
  302.   hist = board_rec->histpos;
  303.   memcpy(occ,board_rec->occ,sizeof(occ));
  304.   for (i = 144,j = 1; j && i-- > remain; )
  305.     if (occ[ideal[i]] != NIL)
  306.       j = 0;
  307.   if (!j) {
  308.     while (find_unambiguous(board_rec,occ,&tile1,&tile2)) {
  309.       remain -= 2;
  310.       history[hist++] = occ[tile1];
  311.       history[hist++] = occ[tile2];
  312.       occ[tile1] = occ[tile2] = NIL; }
  313.     for (i = 144; i-- > remain; )
  314.       if (occ[ideal[i]] != NIL)
  315.     return(0); }
  316.   while (remain < 144) {
  317.     ideal[remain++] = lookup[history[142-remain]];
  318.     ideal[remain++] = lookup[history[144-remain]]; }
  319.   for (tile1 = 144; tile1--;)
  320.     weight[ideal[tile1]] = tile1+1;
  321.   return(1);
  322. }
  323.  
  324. static void depth_scan_initialize(BoardRec *board_rec)
  325. {
  326.   DepthScanRec * const depthscan = &board_rec->depthscan;
  327.  
  328.   #if PRIORITY == 3
  329.   pricount = 0;
  330.   pri_comp = pri_comp0;
  331.   #endif
  332.   memcpy(depthscan->occ,board_rec->occ,sizeof(depthscan->occ));
  333.   depthscan->sp       =
  334.   depthscan->pp       = 0;
  335.   depthscan->remain   = board_rec->remain;
  336.   if (depthscan->remain == 144 || is_board_ideal(board_rec))
  337.     depthscan->status = dsSuccess;
  338.   else
  339.     depthscan->status = dsBusy;
  340.   return;
  341. }
  342.  
  343. static int valid_pos(unsigned char *occ,int i)
  344. {
  345.   int     j;
  346.   
  347.   if (occ[i] != NIL)
  348.     return(0);
  349.   switch (i) {
  350.   case 0:
  351.     return(occ[1] != NIL);
  352.   case 1:
  353.     return (occ[3] != NIL && occ[4] != NIL);
  354.   case 86:
  355.     return(occ[61] != NIL && occ[65] != NIL &&
  356.        occ[81] != NIL && occ[85] != NIL);
  357.   case 143:
  358.     return(occ[140] != NIL && occ[141] != NIL);
  359.   default:
  360.     break; }
  361.   if (board[i].bottom != NIL && occ[board[i].bottom] == NIL)
  362.     return(0);
  363.   for (j = i; j != NIL; j = board[j].left[0])
  364.         if (occ[j] != NIL)
  365.       if (board[i].left[0] != j)
  366.         return(0);
  367.       else
  368.         break;
  369.   for (j = i; j != NIL; j = board[j].right[0])
  370.     if (occ[j] != NIL)
  371.       if (board[i].right[0] != j)
  372.     return(0);
  373.       else
  374.     break;
  375.   return(1);
  376. }
  377.  
  378. static int neighbor(unsigned char *occ,int pos1,int pos2)
  379. {
  380.   if (board[pos1].left[0] == pos2 ||
  381.       board[pos1].right[0] == pos2) {
  382.     if (board[pos1].left[0] == pos2) {
  383.       if (chk(occ,board[pos1].right) != NIL ||
  384.       chk(occ,board[pos2].left) != NIL)
  385.     return(1); }
  386.     else if (chk(occ,board[pos1].left) != NIL ||
  387.          chk(occ,board[pos2].right) != NIL)
  388.       return(1); }
  389.   if (board[pos1].top == pos2 ||
  390.       board[pos2].top == pos1)
  391.     return(1);
  392.   switch (pos1) {
  393.   case 0:
  394.     return(pos2 == 1 || pos2 == 3 || pos2 == 4);
  395.   case 1:
  396.     return(pos2 == 3 || pos2 == 4);
  397.   case 3: case 4:
  398.     return(pos2 == 1 || pos2 == 0);
  399.   case 140: case 141:
  400.     return(pos2 == 143);
  401.   case 143:
  402.     return(pos2 == 140 || pos2 == 141);
  403.   default:
  404.     break; }
  405.   return(0);
  406. }
  407.  
  408. static void initialize_new_board(long seed,unsigned char *occ,
  409.                  unsigned char *ideal,unsigned char *weight,
  410.                  unsigned char *lookup)
  411. {
  412.   int     ob,tile1,tile2,count,obcount;
  413.   int     obs[5],nloop,inc;
  414.   unsigned char *id;
  415.   
  416.   srand(seed);
  417. loop:
  418.   nloop = 0;
  419.   memset(occ,NIL,sizeof(unsigned)*144);
  420.   memset(obs,0,sizeof(obs));
  421.   id = ideal;
  422.   for (obcount = 0; obcount < 144/2; obcount++) {
  423.     ob = 2*(rand()%(144/4))+(obcount >= 144/4);
  424.     inc = rand() & 1 ? 2 : -2;
  425.     for (;;) {
  426.       if (obs[ob/16] & (1 << (ob % 16))) {
  427.     if ((ob += inc) >= 144/2) ob -= 144/2;
  428.     else if (ob < 0) ob += 144/2; }
  429.       else
  430.     break; }
  431.     obs[ob/16] |= (1 << (ob % 16));
  432.     ob *= 2;
  433.   retry:
  434.     tile1 = rand() % 144;
  435.     inc  = rand() & 1 ? 1 : -1;
  436.     count = 0;
  437.     while (!valid_pos(occ,tile1)) {
  438.       if ((tile1 += inc) >= 144) tile1 = 0;
  439.       else if (tile1 < 0) tile1 = 143;
  440.       if (count++ == 144)
  441.     goto loop; }
  442.     occ[tile1] = ob;
  443.     tile2 = rand() % 144;
  444.     inc  = rand() & 1 ? 1 : -1;
  445.     count = 0;
  446.     while (tile1 == tile2 || !valid_pos(occ,tile2)) {
  447.       if ((tile2 += inc) >= 144) tile2 = 0;
  448.       else if (tile2 < 0) tile2 = 143;
  449.       if (count++ == 144)
  450.     goto loop; }
  451.     if (neighbor(occ,tile1,tile2)) {
  452.       occ[tile1] = NIL;
  453.       if (nloop)
  454.     goto loop;
  455.       nloop = 1;
  456.       goto retry; }
  457.     nloop = 0;
  458.     occ[tile2] = ob+1;
  459.     lookup[ob]   = tile1;
  460.     lookup[ob+1] = tile2;
  461.     *id++ = tile1;
  462.     *id++ = tile2; }
  463.   for (tile1 = 144; tile1--;)
  464.     weight[ideal[tile1]] = tile1+1;
  465.   return;
  466. }
  467.  
  468. BoardRec *initialize_board_rec(FD_board *board,BoardRec *board_rec,int seed)
  469. {
  470.   int scoremode = board_rec == NULL;
  471.  
  472.   if (board_rec)
  473.     memset(board_rec,0,sizeof(BoardRec));
  474.   else {
  475.     board_rec = calloc(sizeof(BoardRec),1);
  476.     if (board_rec == NULL) {
  477.       fprintf(stderr,"Out of memory\n");
  478.       exit(1); } }
  479.   board->board->u_vdata      =
  480.   board->board_frame->u_vdata=
  481.   board->status->u_vdata     = board_rec;
  482.   board_rec->ox              = board->board_frame->x;
  483.   board_rec->oy              = board->board_frame->y;
  484.   board_rec->ow              = board->board_frame->w;
  485.   board_rec->oh              = board->board_frame->h;
  486.   board_rec->boardnumeditable= 1;
  487.   board_rec->board           = board;
  488.   board_rec->seed            = abs(seed)%1000000000;
  489.   initialize_new_board(board_rec->seed,board_rec->occ,board_rec->ideal,
  490.                board_rec->weight,board_rec->lookup);
  491.   board_rec->sel0            =
  492.   board_rec->sel1            = NIL;
  493.   board_rec->remain          = 144;
  494.   board_rec->matchcount      = match_count(board_rec->occ,board_rec->lookup,0);
  495.   board_rec->scoremode       = scoremode;
  496.   board_rec->isfastgame      = default_isfastgame;
  497.   memset(board_rec->inverted,NIL,sizeof(board_rec->inverted));
  498.   depth_scan_initialize(board_rec);
  499.   memset(&board_rec->infobox,0xAA,sizeof(InfoBoxRec));
  500.   fl_hide_object(board->pausebox);
  501.   update_info_box(board_rec);
  502.   deactivate_board_num(board_rec);
  503.   return(board_rec);
  504. }
  505.  
  506. static __inline__ int find_tile(unsigned char *occ,int x,int y)
  507. {
  508.   int     i;
  509.   int     best=NIL,maxdepth=NIL;
  510.   int     ox,oy,ow,oh;
  511.   
  512.   for (i = 144; i--;)
  513.     if ((maxdepth == NIL || maxdepth < board[i].depth) &&
  514.     tile_is_removable(occ,i)) {
  515.       tile_pos(i,&ox,&oy,&ow,&oh,0,0,0,0);
  516.       if (ox <= x && oy <= y && x < ox+ow && y < oy+oh) {
  517.     maxdepth = board[i].depth;
  518.     best = i; } }
  519.   return(best);
  520. }
  521.  
  522. static void select_tile(BoardRec *board_rec,int tile)
  523. {
  524.   unsigned char *occ  = board_rec->occ;
  525.   unsigned char sel0  = board_rec->sel0;
  526.   unsigned char sel1  = board_rec->sel1;
  527.   int           top,x,y,w,h;
  528.   
  529.   if (tile == NIL || occ[tile] == NIL ||
  530.       ((top = board[tile].top) != NIL && occ[top] != NIL))
  531.     return;
  532.   if (tile == sel0 || tile == sel1)
  533.     if (tile == sel0) board_rec->sel0 = NIL; else board_rec->sel1 = NIL;
  534.   else if (sel0 != NIL && occ[tile]/4 == occ[sel0]/4)
  535.     board_rec->sel1 = tile;
  536.   else if (sel1 != NIL && occ[tile]/4 == occ[sel1]/4)
  537.     board_rec->sel0 = tile;
  538.   else if (sel0 != NIL || sel1 != NIL)
  539.     return;
  540.   else
  541.     board_rec->sel0 = tile;
  542.   tile_pos(tile,&x,&y,&w,&h,0,0,0,0);
  543.   draw_area(x,y,w,h,board_rec);
  544.   XFlush(board_rec->disp);
  545.   return;
  546. }
  547.  
  548. static void remove_tile(BoardRec *board_rec,int tile)
  549. {
  550.   int x,y,w,h;
  551.   
  552.   board_rec->history[board_rec->histpos] = board_rec->occ[tile];
  553.   if (++board_rec->histpos < 144)
  554.     board_rec->histstep[board_rec->histpos] =
  555.       board_rec->histstep[board_rec->histpos-1];
  556.   board_rec->occ[tile] = NIL;
  557.   board_rec->remain--;
  558.   tile_pos(tile,0,0,0,0,&x,&y,&w,&h);
  559.   if (board_rec->sel0 == tile) board_rec->sel0 = NIL;
  560.   else if (board_rec->sel1 == tile) board_rec->sel1 = NIL;
  561.   draw_area(x,y,w,h,board_rec);
  562.   XFlush(board_rec->disp);
  563.   return;
  564. }
  565.  
  566. static void release_mouse_button(BoardRec *board_rec)
  567. {
  568.   XEvent        event;
  569.  
  570.   do {
  571.     if (board_rec->depthscan.status == dsBusy)
  572.       depth_scan(board_rec);
  573.     else
  574.       usleep(50*1000l);
  575.     update_info_box(board_rec);
  576.   } while (!XCheckMaskEvent(board_rec->disp,ButtonReleaseMask,&event) ||
  577.        event.xbutton.state & ~(Button1Mask << (event.xbutton.button-1))
  578.        & (Button1Mask|Button2Mask|Button3Mask));
  579.   return;
  580. }
  581.  
  582. void handle_mouse_push(int mx,int my,int key,BoardRec *board_rec)
  583. {
  584.   unsigned char tile1,tile2;
  585.  
  586.   deactivate_board_num(board_rec);
  587.   switch (key) {
  588.   case 1:
  589.     if ((tile1 = find_tile(board_rec->occ,mx,my)) != NIL) {
  590.       select_tile(board_rec,tile1);
  591.       release_mouse_button(board_rec);
  592.       if (board_rec->sel0 != NIL && board_rec->sel1 != NIL) {
  593.     board_rec->histstep[board_rec->histpos] = board_rec->histpos;
  594.     for (;;) {
  595.       remove_tile(board_rec,board_rec->sel0);
  596.       remove_tile(board_rec,board_rec->sel1);
  597.       board_rec->matchcount = match_count(board_rec->occ,
  598.                           board_rec->lookup,NULL);
  599.       update_info_box(board_rec);
  600.       if (!board_rec->isfastgame || !board_rec->remain ||
  601.           !find_unambiguous(board_rec,board_rec->occ,&tile1,&tile2))
  602.         break;
  603.       board_rec->scoremode = 0;
  604.       select_tile(board_rec,tile1);
  605.       select_tile(board_rec,tile2); }
  606.     if (!board_rec->time && board_rec->matchcount)
  607.       board_rec->time    =time(NULL);
  608.     else if (board_rec->time > 0 && !board_rec->matchcount)
  609.       if ((board_rec->time-=time(NULL)) == 0)
  610.         board_rec->time  =-1;
  611.     if (board_rec->depthscan.status != dsFail)
  612.       depth_scan_initialize(board_rec);
  613.     update_info_box(board_rec); } }
  614.     break;
  615.   case 2:
  616.     if (!board_rec->matchcount)
  617.       release_mouse_button(board_rec);
  618.     else {
  619.       unsigned char inverted[144],sel;
  620.       #if DRAWSUGGEST == 1
  621.       int           tile;
  622.       #endif
  623.       if ((sel = board_rec->sel0) != NIL ||
  624.       (sel = board_rec->sel1) != NIL)
  625.     select_tile(board_rec,sel);
  626.       match_count(board_rec->occ,board_rec->lookup,board_rec->inverted);
  627.       memcpy(inverted,board_rec->inverted,sizeof(inverted));
  628.       board_rec->scoremode = 0;
  629.       if (board_rec->time == 0)
  630.     board_rec->time = time(NULL);
  631.       #if DRAWSUGGEST == 1
  632.       for (tile = 144; tile--; )
  633.     if (inverted[tile] != NIL) {
  634.       int x,y,w,h;
  635.       tile_pos(tile,&x,&y,&w,&h,0,0,0,0);
  636.       draw_area(x,y,w,h,board_rec); }
  637.       #else
  638.       draw_all_tiles(board_rec);
  639.       #endif
  640.       update_info_box(board_rec);
  641.       release_mouse_button(board_rec);
  642.       memset(board_rec->inverted,NIL,sizeof(board_rec->inverted));
  643.       #if DRAWSUGGEST == 1
  644.       for (tile = 144; tile--; )
  645.     if (inverted[tile] != NIL) {
  646.       int x,y,w,h;
  647.       tile_pos(tile,&x,&y,&w,&h,0,0,0,0);
  648.       draw_area(x,y,w,h,board_rec); }
  649.       #else
  650.       draw_all_tiles(board_rec);
  651.       #endif
  652.       if (sel != NIL)
  653.     select_tile(board_rec,sel); }
  654.     break;
  655.   case 3: {
  656.     int i;
  657.     if ((i = board_rec->sel0) != NIL ||
  658.     (i = board_rec->sel1) != NIL)
  659.       select_tile(board_rec,i);
  660.     release_mouse_button(board_rec);
  661.     break; }
  662.   default:
  663.     break; }
  664.   return;
  665. }
  666.  
  667. void game_undo_move(BoardRec *board_rec)
  668. {
  669.   int i,p,x,y,w,h;
  670.  
  671.   deactivate_board_num(board_rec);
  672.   if ((i = board_rec->sel0) != NIL ||
  673.       (i = board_rec->sel1) != NIL)
  674.     select_tile(board_rec,i);
  675.   if (board_rec->remain == 144)
  676.     return;
  677.   if (board_rec->time <= 0)
  678.     if ((board_rec->time += time(NULL)) == 0)
  679.       board_rec->time = 1;
  680.   board_rec->scoremode  = 0;
  681.   while (board_rec->remain != 144) {
  682.     p = --board_rec->histpos;
  683.     i = board_rec->lookup[board_rec->history[p]];
  684.     board_rec->occ[i] = board_rec->history[p];
  685.     tile_pos(i,0,0,0,0,&x,&y,&w,&h);
  686.     draw_area(x,y,w,h,board_rec);
  687.     if (board_rec->remain++ & 1) {
  688.       board_rec->matchcount=match_count(board_rec->occ,board_rec->lookup,NULL);
  689.       update_info_box(board_rec); }
  690.     if (p == board_rec->histstep[p])
  691.       break; }
  692.   depth_scan_initialize(board_rec);
  693.   update_info_box(board_rec);
  694.   return;
  695. }
  696.  
  697. void handle_status_push(int key,BoardRec *board_rec)
  698. {
  699.   int i;
  700.  
  701.   if (key != 1) {
  702.     handle_mouse_push(-1,-1,key,board_rec);
  703.     return; }
  704.   deactivate_board_num(board_rec);
  705.   if (!board_rec->remain ||
  706.       (board_rec->depthscan.status != dsSuccess &&
  707.        board_rec->depthscan.status != dsSuccessSelected))
  708.     return;
  709.   board_rec->depthscan.status = dsSuccessSelected;
  710.   board_rec->scoremode = 0;
  711.   if (!board_rec->time)
  712.     board_rec->time = time(NULL);
  713.   if ((i = board_rec->sel0) != NIL ||
  714.       (i = board_rec->sel1) != NIL)
  715.     select_tile(board_rec,i);
  716.   select_tile(board_rec,board_rec->ideal[board_rec->remain-1]);
  717.   select_tile(board_rec,board_rec->ideal[board_rec->remain-2]);
  718.   release_mouse_button(board_rec);
  719.   board_rec->histstep[board_rec->histpos] = board_rec->histpos;
  720.   board_rec->depthscan.status = dsSuccess;
  721.   for (;;) {
  722.     remove_tile(board_rec,board_rec->sel0);
  723.     remove_tile(board_rec,board_rec->sel1);
  724.     board_rec->matchcount = match_count(board_rec->occ,board_rec->lookup,NULL);
  725.     update_info_box(board_rec);
  726.     if (!board_rec->isfastgame || !board_rec->remain ||
  727.     !find_unambiguous(board_rec,board_rec->occ,
  728.               &board_rec->sel0,&board_rec->sel1))
  729.       break;
  730.     board_rec->depthscan.status = dsBusy; }
  731.   if (!board_rec->matchcount)
  732.     if (board_rec->time > 0) {
  733.       if ((board_rec->time -= time(NULL)) == 0)
  734.     board_rec->time = -1; }
  735.     else if (board_rec->time == 0)
  736.       board_rec->time = -1;
  737.   if (board_rec->depthscan.status != dsSuccess)
  738.     depth_scan_initialize(board_rec);
  739.   update_info_box(board_rec);
  740.   return;
  741. }
  742.